﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using CakeAnimation;


namespace CharacterAnimationEditor
{
    public class AnimationControlGUI
    {
        Skeleton m_Skeleton;

        SkeletonView m_SkeletonView;
        IKSolver m_IKSolver;

        Vector2 m_ClipboardPos;
        string m_ClipboardBoneName;

        float m_MouseT = 0.0f;

        public AnimationControlGUI(Context context)
        {
            m_Skeleton = new Skeleton(context.AnimationContext, "SkeletonRig.txt");
            m_SkeletonView = new SkeletonView();
            m_SkeletonView.MySkeleton = m_Skeleton;
            m_SkeletonView.Offset = new Vector2(100, 100);
            m_SkeletonView.Scale = 0.6f;
            m_SkeletonView.HandleControlTints = true;
            m_SkeletonView.ZOffset = 0.2f;

            m_IKSolver = new IKSolver();
        }

        public void Update(Context context)
        {
            m_SkeletonView.MySkeleton = context.CurrentKeyFrame.Pose;

            if (context.MousePos.Y > 480)
            {
                return;
            }


            SetHoveredBone(context);

            SetFixedBone(context);

            SetSelectedBone(context);

            UpdateDrag(context);

            UpdateForwardKinematics(context);

            SetCurrentKeyFrame(context);
            UpdateMousePress(context);

            if (context.CurrKeyState.IsKeyDown(Keys.LeftControl))
            {
                if (context.CurrKeyState.IsKeyDown(Keys.Left))
                {
                    context.Zoom -= context.DeltaTime;
                }
                if (context.CurrKeyState.IsKeyDown(Keys.Right))
                {
                    context.Zoom += context.DeltaTime;
                }

                if (context.CurrKeyState.IsKeyDown(Keys.C))
                {
                    if (context.HoveredBone != null)
                    {
                        m_ClipboardPos = context.HoveredBone.Position;
                        m_ClipboardBoneName = context.HoveredBone.Name;
                    }
                }

                if (context.CurrKeyState.IsKeyDown(Keys.V) && !string.IsNullOrEmpty(m_ClipboardBoneName))
                {
                    Bone b = context.CurrentKeyFrame.Pose.GetBone(m_ClipboardBoneName);
                    Vector2 diff = m_ClipboardPos - b.Position;
                    context.CurrentKeyFrame.Pose.RootBone.LocalPosition += diff;
                    context.CurrentKeyFrame.Pose.RootBone.UpdateTransform();
                }
            }
            else
            {
                if (context.CurrKeyState.IsKeyDown(Keys.Left))
                {
                    context.CameraPos.X -= context.DeltaTime * 100;
                }
                if (context.CurrKeyState.IsKeyDown(Keys.Right))
                {
                    context.CameraPos.X += context.DeltaTime * 100;
                }

                if (context.CurrKeyState.IsKeyDown(Keys.Up))
                {
                    context.CameraPos.Y -= context.DeltaTime * 100;
                }
                if (context.CurrKeyState.IsKeyDown(Keys.Down))
                {
                    context.CameraPos.Y += context.DeltaTime * 100;
                }

                m_SkeletonView.Offset = new Vector2(100, 100) + context.CameraPos;
            }

            context.Zoom = Math.Max(0.1f, Math.Min(context.Zoom, 0.6f));

            context.HelpDisplay.SetCaption("Animation control");
            context.HelpDisplay.SetText("CB=" + m_ClipboardBoneName + "@" + m_ClipboardPos.ToString());

            if (context.Animation.Loopable)
            {
                Vector2 pos = context.Animation.GetLastKeyframe().Pose.RootBone.LocalPosition;
                context.Animation.GetPoseAt(0.0f, context.Animation.GetLastKeyframe().Pose);
                context.Animation.GetLastKeyframe().Pose.RootBone.LocalPosition = pos;
                context.Animation.GetLastKeyframe().Pose.RootBone.UpdateTransform();
            }
        }

        private void UpdateMousePress(Context context)
        {
            if (context.CurrMouseState.LeftButton == ButtonState.Pressed)
            {
                m_MouseT += context.DeltaTime;
            }
            else
            {
                m_MouseT = 0.0f;
            }
        }

        private void SetCurrentKeyFrame(Context context)
        {
            if (context.MousePos.Y > 500)
            {
                return;
            }

            int scroll = context.MouseScroll;
            if (context.PrevKeyState.IsKeyUp(Keys.Q) && context.CurrKeyState.IsKeyDown(Keys.Q))
            {
                scroll = -1;
            }
            if (context.PrevKeyState.IsKeyUp(Keys.W) && context.CurrKeyState.IsKeyDown(Keys.W))
            {
                scroll = 1;
            }

            if (scroll != 0)
            {
                int index = context.Animation.m_Keyframes.FindIndex(delegate(KeyFrame kf) { return kf == context.CurrentKeyFrame; });
                index += scroll;
                if (0 <= index && index < context.Animation.m_Keyframes.Count)
                {
                    context.SetCurrentKeyFrame(context.Animation.m_Keyframes[index]);
                }
            }
        }

        private void UpdateForwardKinematics(Context context)
        {
            if (context.SelectedBone != null && context.CurrMouseState.RightButton == ButtonState.Pressed)
            {
                float xdiff = context.GetMouseMovement().X;
                context.SelectedBone.LocalRotation -= xdiff *= 0.01f;
            }
        }

        private void UpdateDrag(Context context)
        {
            m_IKSolver.SetTip(null);
            if (context.SelectedBone != null && context.CurrMouseState.LeftButton == ButtonState.Pressed)
            {
                if (context.SelectedBone.Fixed || context.SelectedBone.Parent == null)
                {
                    float scale = m_SkeletonView.Scale;
                    if (context.CurrKeyState.IsKeyDown(Keys.LeftShift))
                    {
                        scale *= 500f;
                    }
                    context.SelectedBone.LocalPosition += context.GetMouseMovement() / scale;
                }
                else
                {
                    float scale = context.GetWindowScale();
                    scale *= m_SkeletonView.Scale;
                    m_IKSolver.SetTip(context.SelectedBone);
                    Vector2 mousePos = (context.MousePos - m_SkeletonView.Offset * context.GetWindowScale()) / scale;
                    m_IKSolver.Target = mousePos;
                    m_IKSolver.Update(context.AnimationContext);
                }
            }
        }

        private void SetSelectedBone(Context context)
        {
            if (context.CurrKeyState.IsKeyDown(Keys.LeftControl))
            {
                //context.SelectedBone = null;
                //context.HoveredBone = context.CurrentKeyFrame.Pose.GetBone(clipboardBoneName);
                //return;
            }

            if (context.PrevMouseState.LeftButton == ButtonState.Released &&
                context.CurrMouseState.LeftButton == ButtonState.Pressed ||
                context.PrevMouseState.RightButton == ButtonState.Released &&
                context.CurrMouseState.RightButton == ButtonState.Pressed)
            {
                context.SelectedBone = context.HoveredBone;

                //if (context.HoveredBone == null)
                //{
                //    if (context.SelectedBone != null)
                //        context.SelectedBone.Selected = false;
                //    context.SelectedBone = null;
                //}
                //else if (context.SelectedBone == null)
                //{
                //    context.SelectedBone = context.HoveredBone;
                //    context.SelectedBone.Selected = true;
                //}
            }
        }

        private void SetFixedBone(Context context)
        {
            if (context.PrevMouseState.MiddleButton == ButtonState.Released && context.CurrMouseState.MiddleButton == ButtonState.Pressed)
            {
                if (context.HoveredBone != null)
                {
                    context.HoveredBone.Fixed = !context.HoveredBone.Fixed;
                }
            }
        }

        private void SetHoveredBone(Context context)
        {
            if (context.HoveredBone != null)
            {
                context.HoveredBone = null;
            }

            float scale = context.GetWindowScale();
            scale *= m_SkeletonView.Scale;
            Vector2 mousePos = (context.MousePos - m_SkeletonView.Offset * context.GetWindowScale()) / scale;
            context.HoveredBone = context.CurrentKeyFrame.Pose.GetClosestBone(mousePos);
        }


        public void Draw(Context context)
        {
            m_SkeletonView.Scale = context.Zoom;
            m_SkeletonView.Draw(context);

            float scale = context.GetWindowScale();
            scale *= m_SkeletonView.Scale;
            Vector2 mousePos = (context.MousePos - m_SkeletonView.Offset * context.GetWindowScale()) / scale;
            mousePos = mousePos * m_SkeletonView.Scale * context.GetWindowScale() + m_SkeletonView.Offset * context.GetWindowScale();


            if (context.CurrMouseState.LeftButton == ButtonState.Pressed)
            {
                context.SpriteBatch.DrawString(
                    context.Font,
                   "*",
                    mousePos,
                    Color.Black);
            }

            if (context.HoveredBone != null)
            {
                if (context.CurrKeyState.IsKeyDown(Keys.LeftShift))
                {
                    string boneName = context.HoveredBone.Name;
                    Bone firstBone = context.Animation.m_Keyframes[0].Pose.GetBone(boneName);
                    Vector2 relPos = context.HoveredBone.Position - firstBone.Position;

                    context.SpriteBatch.DrawString(
                        context.Font,
                        relPos.ToString(),
                        mousePos,
                        Color.Yellow);
                }

                //context.Sb.DrawString(
                //    context.Font,
                //    context.HoveredBone.ToString(),
                //    new Vector2(300, 200),
                //    Color.Black);
            }
        }
    }
}
